#include "ULCore_PredictByAC.h"
#include "VSDL_tools.h"

//AC(8) is the center line
#define EXP_VAL	5
#define EXP_GAP	6

#define PREDICT_AC_FIXUP	1

static int AC_4[5] = {5, 6, 7, 8, 9};
static int AC_5_7[5] = {6, 7, 8, 9, 10};
static int AC_8[5] = {EXP_VAL - 1, EXP_VAL, EXP_VAL + 1, EXP_VAL + 2, EXP_VAL + 3};
static int AC_9[5] = {4, 5, 6, 7, 8} ;
static int AC_10[5] = {3, 4, 6, 7, 8};

static int PickNumber(int *numbers, int size)
{
	return numbers[VSDL_Tool::Rand() % size];
}

int ULC_PredictByAC::PredictNextSerial(ULC_Serial &serial, ULC_History &historyData)
{
	ULC_Serial *serials;
	ULC_Serial *latestSerial;
	ULC_Serial *tmpSerial; 
	int i;
	ULC_ACData acData;
	int latestAC;
	int predictedAC;
	ULC_Statistic stat;
	bool validNumbers[UL_BALL_MAX_RED];

	for (i = 0; i < UL_BALL_MAX_RED; i++){
		validNumbers[i] = true;
	}
	//Get latest serial's AC
	tmpSerial = historyData.GetLatestSerial();
	acData.Caculate(&tmpSerial->sortedBalls);
	latestAC = acData.ac;

	cout << acData;
	//Generate random pool using latest AC
	redPools[0].Reset();
	for (i = 0; i < acData.dtDiff; i++){
		validNumbers[acData.dtDataFinal[i] - 1] = false;
	}
	
	//Add valid numbers to random pool
	for (i = 0; i < UL_BALL_MAX_RED; i++){
		if (validNumbers[i]){
			redPools[0].AddNumber(i + 1);
		}
	}

	stat.ParseHistoryData(historyData);
	SetupRedPools(stat);
	SetupBluePool(stat);

	if (latestAC <= 4){
		predictedAC = PickNumber(AC_4, 5);
	}else if (latestAC <= 7){
		predictedAC = PickNumber(AC_5_7, 5);
	}else if (latestAC == 9){
		predictedAC = PickNumber(AC_9, 5);
	}else if (latestAC == 10){
		predictedAC = PickNumber(AC_10, 5);
	}else{
		int nSerials = 99999999;
		int index;
		int gap = 0;

		//AC = 8
		//Get all serials
		serials = historyData.GetLatestSerials(nSerials);

		index = nSerials - 1;
		//Get Last serial with AC(8)
		while (index >= 0){
			acData.Caculate(&serials[index].sortedBalls);

			if (acData.ac == 8){
				break;
			}

			index--;
			gap++;
		}

		if (gap >= EXP_GAP){
			//It's been a long time since last time when AC 8 appeared
			predictedAC = 8;
		}else{
			predictedAC = PickNumber(AC_8, 5);
		}
	}

	//Use AC to predicted next serial
	bool predicting = true;

	while (predicting){
		int number;

		for (int i = 0; i < UL_RED_BALLS_COUNT; i++){
			number = redPools[0].GetNumber();

			while (serial.actualOutBalls.IsRedBallExisted(number)){
				number = redPools[0].GetNumber();
			}

			serial.actualOutBalls.reds[i] = number;
		}		

		acData.Caculate(&serial.actualOutBalls);
		
		if (acData.ac <= predictedAC + PREDICT_AC_FIXUP && acData.ac >= predictedAC - PREDICT_AC_FIXUP){
			predicting = false;
		}
	}

	serial.sortedBalls = serial.actualOutBalls;
	serial.sortedBalls.EnableOutputBlue();
	serial.sortedBalls.SortRedBalls();
	
	serial.sortedBalls.blue = bluePool.GetNumber();
#ifdef ULC_PREDICTBYAC_DEBUG
	cout << __func__ << ":Predicted serial: " << endl;
	cout << serial;
#endif

	return 0;
}
